// Header guard
#ifndef VAR_H
#define VAR_H

// Header files
#include <string>
#include <vector>
#include <stdint.h>
#include <stdlib.h>
#include <array>

using namespace std;
enum varType { VOLUME_HEADER, STORE_HEADER, UN_KNOWN};

struct VARIABLE_STORE_HEADER_PACK {
  string  Signature;
  uint32_t  Size;
  uint8_t   Format;
  uint8_t   State;
//  uint16_t  Reserved;
//  uint32_t  Reserved1;
} ;

///
/// Single Variable Data Header Structure.
///
struct VARIABLE_HEADER_PACK {
  uint16_t      StartId;
  uint8_t       State;
  uint8_t       Reserved;
  uint32_t      Attributes;
  uint32_t      NameSize;
  uint32_t      DataSize;
  string      VendorGuid;
} ;


struct EFI_FV_BLOCK{
  uint32_t NumBlocks;
  uint32_t Length;
} ;

struct FIRMWARE_VOLUME_HEADER {
  array<uint8_t, 16>        ZeroVector;
  string                    FileSystemGuid;
  uint64_t                  FvLength;
  uint32_t                  Signature;
  uint32_t                  Attributes;
  uint16_t                  HeaderLength;
  uint16_t                  Checksum;
  uint16_t                  ExtHeaderOffset;
//  uint8_t                   Reserved[1];
  uint8_t                   Revision;
  EFI_FV_BLOCK              BlockMap[1];
};

///
/// type of EFI FVB attribute
///
#define VOLUME_HEADER_MAX_LEN 0x50
struct EFI_VOLUME_HEADER_PACK {
  uint64_t                                offset;
  uint64_t                                size;
  array<uint8_t, VOLUME_HEADER_MAX_LEN>   data{};
  FIRMWARE_VOLUME_HEADER                  volumeHeader;
} ;

#define VARIABLE_STORE_HEADER_MAX_LEN 0x20
#define ALL_VARIABLES_MAX_LEN 0x100000
struct EFI_VARIABLES_PACK {
  uint64_t                                offset;
  uint64_t                                size;
  array<uint8_t, ALL_VARIABLES_MAX_LEN>   data{};
} ;

struct EFI_VARIABLE_STORE_HEADER_PACK {
  uint64_t                                offset;
  uint64_t                                size;
  array<uint8_t, VARIABLE_STORE_HEADER_MAX_LEN> data{};
  VARIABLE_STORE_HEADER_PACK              storeHeader;
  EFI_VARIABLES_PACK                      variables;
} ;

#define VARIABLE_MAX_LEN 0xA000
#define VARIABLE_HEADER_LEN (VARIABLE_MAX_LEN + 0x20)
struct VARIABLE_NAME_PACK {

  uint64_t                                offset;
  uint64_t                                size;
  string                                  name;
} ;


struct VARIABLE_DATA_PACK {
  uint64_t                                offset;
  uint64_t                                size;
  array<uint8_t, VARIABLE_MAX_LEN>        data{};
} ;

struct VARIABLE_PACK {
  VARIABLE_NAME_PACK name;
  VARIABLE_DATA_PACK data;
} ;
struct EFI_VARIABLE_PACK {
  uint64_t                               offset;
  uint64_t                               size;
  array<uint8_t, VARIABLE_HEADER_LEN>    data{};
  VARIABLE_HEADER_PACK                   variableHeader;
  VARIABLE_PACK                          variable;
} ;
// Function prototypes
/*
Name: getVarType
Purpose: Gets VAR type
*/
varType getVarType(const string &buffer, string guid);
void getVarHeaderInfo(varType type, const string &buffer, vector<EFI_VOLUME_HEADER_PACK> &volumePackages);
void displayVarHeaderInfo(const vector<EFI_VOLUME_HEADER_PACK> &volumePackages);
void getVarStoreHeaderInfo( varType type, const string &buffer, vector<EFI_VOLUME_HEADER_PACK> &volumePackages, vector<EFI_VARIABLE_STORE_HEADER_PACK> &storePackages);
void displayVarStoreHeaderInfo(const vector<EFI_VARIABLE_STORE_HEADER_PACK> &storePackages);
void getVariableInfo( varType type, const string &buffer, vector<EFI_VOLUME_HEADER_PACK> &volumePackages, \
                    vector<EFI_VARIABLE_STORE_HEADER_PACK> &storePackages,\
                    vector<EFI_VARIABLE_PACK> &variablePackages);
void displayVariableInfo(const vector<EFI_VARIABLE_PACK> &variablePackages);
void getNVarInfo(const string &buffer, string NVARGuid, vector<EFI_VARIABLE_PACK> &variablePackages);
#endif
